package Cluster;

import java.util.ArrayList;
import java.util.List;

import Application.ImageGenerator;
import Application.ReadFileGenerateor;
import MyLoader.MyLoader;
import XmlLoader.FGObjProcess;
import XmlLoader.FGObjectTrajectoryStructure;
import XmlLoader.Position;

public class KMeansCluster {
	
	protected int KValue = 0;
	protected int whichMatric = 0, whichMainTraj = 0;
	protected Position min = null, max = null;
	protected double stopCondit = 0;
	protected String filePathBG = null;
	protected ArrayList<ClusterBulk> listCluster = null;
	public KMeansCluster(int KValue, int whichMatric, int whichMainTraj, int stopCondit,
			Position min, Position max, String filePathBG) {
		this.KValue = KValue;
		this.whichMatric = whichMatric;
		this.whichMainTraj = whichMainTraj;
		this.stopCondit = stopCondit;
		this.min = min;
		this.max = max;
		this.filePathBG = filePathBG;
	}
	
	protected void __001_initialClusterCenter() {
		this.listCluster = new ArrayList<ClusterBulk>();
		Trajectory newTrajMain = null;
		ClusterBulk newCB = null;
		int index = 0;
		while(index < this.KValue) {
			//create new cluster
			newCB = new ClusterBulk(index, this.whichMainTraj);
			//create new main trajectory
			newTrajMain = new Trajectory();
			newTrajMain.ACT001_addPoint(this.__002_randomMinMaxRange());
			//set main trajectory
			newCB.ACT002_initialMainTraj(newTrajMain);
			this.listCluster.add(newCB);
			//show message
			System.out.println("Cluster " + newCB.clusterID + 
					" is created, main point = (" + 
					newCB.GET001_mainTraj().GET002_point(0).x +
					"," + newCB.GET001_mainTraj().GET002_point(0).y + ")");
			index = index + 1;
		}
	}
	
	protected Position __002_randomMinMaxRange() {
		Position p = new Position();
		p.x = (int)(Math.random()*(this.max.x - this.min.x)) + this.min.x;
		p.y = (int)(Math.random()*(this.max.y - this.min.y)) + this.min.y;
		return p;
	}
	
	protected void __003_runClusteringOneTime(ArrayList<Trajectory> listTraj) {
		int indexTraj = 0, indexCluster = 0;
		int indexMostLike = 0;
		double dist = 0.0, distMin = 0.0;
		while(indexTraj < listTraj.size()) {
			//initial
			indexMostLike = -1;
			distMin = 1000000;
			//compare distance from current trajectory to each cluster main
			indexCluster = 0;
			while(indexCluster < this.listCluster.size()) {
				dist = this.__004_compareTwoTrajDist(this.listCluster.get(indexCluster).GET001_mainTraj(),
						listTraj.get(indexTraj));
				//check isLike
				if(dist < distMin) {
					distMin = dist;
					indexMostLike = indexCluster;
				}
				indexCluster = indexCluster + 1;
			}
			//add new trajectory to right cluster
			this.listCluster.get(indexMostLike).ACT001_insertNewTraj(listTraj.get(indexTraj));
			indexTraj = indexTraj + 1;
		}
	}
	
	protected double __004_compareTwoTrajDist(Trajectory traj1, Trajectory traj2) {
		double countResult = 0.0;
		switch(this.whichMatric) {
		case Matric.MATRIC_DTW :
			countResult = Matric.DTW(traj1, traj2);
			break;
		}
		return countResult;
	}
	
	protected void __005_clearallClusterEle(){
		int index = 0;
		while(index < this.listCluster.size()) {
			this.listCluster.get(index).ACT004_clearCluster();
			index = index + 1;
		}
	}
	
	public void ACT001_doCluster(ArrayList<Trajectory> listTraj) {
		int doTime = 0;
		boolean isStop = false;
		boolean isFirst = true;
		int index = 0;
		Trajectory mainBefore = null, mainCur = null;
		double totalDist = 0;
		//initial random main trajectory for each cluster
		System.out.println("Do initial each cluster center");
		this.__001_initialClusterCenter();
		ImageGenerator.GenCluster(doTime + ".png", this.listCluster, this.max.x, this.max.y, this.filePathBG);
		//do cluster
		while(!isStop) {
			System.out.println("Clear cluster");
			this.__005_clearallClusterEle();
			System.out.println("Do cluster");
			this.__003_runClusteringOneTime(listTraj);
			//check whether do next
			totalDist = 0.0;
			if(!isFirst) {
				index = 0;
				while(index < this.listCluster.size()) {
					//compare distance between before&curent distance of mainTraj
					mainBefore = this.listCluster.get(index).GET001_mainTraj();
					this.listCluster.get(index).ACT003_countMainTraj();
					mainCur = this.listCluster.get(index).GET001_mainTraj();
					totalDist = totalDist + this.__004_compareTwoTrajDist(mainBefore, mainCur);
					index = index + 1;
				}
				doTime = doTime + 1;
				//show result
				System.out.println("Result totalDist = " + totalDist);
				//show cluster
				ImageGenerator.GenCluster(doTime + ".png", this.listCluster, this.max.x, this.max.y, this.filePathBG);
				//if average distance < stopCondit, stop loop
				if(totalDist/this.KValue <= this.stopCondit) {
					isStop = true;
				}
			}
			isFirst = false;
		}
		ImageGenerator.GenClusterOneByOne("D:\\GenVidTraj\\Video\\SANY0943_cut\\KMeans\\K_4", listCluster, this.max.x, this.max.y, this.filePathBG);
	}
	public static void main(String[] args) {
		//generate list trajectory index
		System.out.println("Generate trajectory index file");
		new ReadFileGenerateor().ACT001_genFile(args[0], Integer.parseInt(args[1]), Integer.parseInt(args[2]));
				
		//load trajectory xml data
		System.out.println("Load trajectory xml file");
		FGObjProcess fgObj = new FGObjProcess(args[3]);
		List<String> list_objIndex = fgObj.ACT004_getStringList(args[0]);
		List<FGObjectTrajectoryStructure> list = new MyLoader().ACT001_getListOfObj(args[3], list_objIndex);
		
		//trajectory structure transformation
		ArrayList<Trajectory> listTraj = new ArrayList<Trajectory>();
		int index = 0;
		while(index < list.size()) {
			listTraj.add(new Trajectory(list.get(index), 0, 0, list.get(index).GET002_nNumberOfPoint()));
			list.remove(index);
			//index = index + 1;
		}
		//do cluster
		KMeansCluster kc = new KMeansCluster(4, Matric.MATRIC_DTW, MainTraj.MAINTRAJ_AVG,
				0, new Position(0,0), new Position(320,240), "D:\\GenVidTraj\\Video\\SANY0943_cut\\BG\\0019000.jpg");
		kc.ACT001_doCluster(listTraj);
	}
}
